/*
 * Copyright 2022 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package stringescapecodes

import com.google.j2cl.integration.testing.Asserts.assertEquals
import com.google.j2cl.integration.testing.Asserts.assertTrue

/** Test String escape codes. */
const val DEL_CHARACTER = "" + 127.toChar()

fun main(vararg unused: String) {
  testEmptyStringLiteral()
  testSpecialEscapes()
  testUnicodeEscapes()
  // Kotlin does not support octal escape sequence
  // testOctalEscapes()
  testInvalidEscapes()
  testInvalidEscapes_veryLargeStringLiteral()
}

private fun testEmptyStringLiteral() {
  assertTrue("".length == 0)
}

private fun testSpecialEscapes() {
  assertTrue("\b" == 8.toChar().toString())
  assertTrue("\t" == 9.toChar().toString())
  assertTrue("\n" == 10.toChar().toString())
  assertTrue("\u000c" == 12.toChar().toString())
  assertTrue("\r" == 13.toChar().toString())
  assertTrue("\"" == 34.toChar().toString())
  assertTrue("\'" == 39.toChar().toString())
  assertTrue("\\" == 92.toChar().toString())
  assertTrue(DEL_CHARACTER == 127.toChar().toString())
}

private fun testUnicodeEscapes() {
  assertTrue("\u0000".length == 1)

  // This is how the gothic letter "faihu" is represented in unicode.
  val faihu = "\uD800\uDF46"
  assertEquals(faihu, "𐍆")
  assertTrue(faihu.codePointAt(0) == 0x10346)
  assertTrue(faihu.codePointCount(0, faihu.length) == 1)
  // This string has 1 codepoint but its length as a string is 2.
  assertTrue(faihu.length == 2)

  assertTrue("\uFFFF"[0].code == 0xFFFF)
  assertTrue("\uFFFF".length == 1)
}

// Kotlin does not support octal escape sequence
// private fun testOctalEscapes() {
//   assertTrue("\0" == 0.toChar().toString())
//   assertTrue("\1" == 1.toChar().toString())
//   assertTrue("\2" == 2.toChar().toString())
//   assertTrue("\3" == 3.toChar().toString())
//   assertTrue("\4" == 4.toChar().toString())
//   assertTrue("\5" == 5.toChar().toString())
//   assertTrue("\6" == 6.toChar().toString())
//   assertTrue("\7" == 7.toChar().toString())
//   assertTrue("\00" == 0.toChar().toString())
//   assertTrue("\01" == 1.toChar().toString())
//   assertTrue("\02" == 2.toChar().toString())
//   assertTrue("\03" == 3.toChar().toString())
//   assertTrue("\04" == 4.toChar().toString())
//   assertTrue("\05" == 5.toChar().toString())
//   assertTrue("\06" == 6.toChar().toString())
//   assertTrue("\07" == 7.toChar().toString())
//   assertTrue("\55" == (5 * 8 + 5).toChar().toString())
//   assertTrue("\055" == (5 * 8 + 5).toChar().toString())
//   assertTrue("\155" == (1 * 64 + 5 * 8 + 5).toChar().toString())
//   assertTrue("\0155" == (1 * 8 + 5).toChar().toString() + "5")
//   assertTrue("\u001b[31m" == "\u001b[31m")
// }

private fun testInvalidEscapes() {
  // Even though the escape sequence "\\uXXXX" has a meaning in Unicode, in Java each of those
  // is interpreted as the numeric value of a char. It is possible to construct strings that
  // are not valid unicode strings, such as the ones here where there is only the first character
  // for a surrogate pair.
  assertTrue("\uD801"[0].code == 0xd801)
  assertTrue("\uD800"[0].code == 0xd800)
  assertTrue("\uDC00"[0].code == 0xdC00)
  // An invalid surrogate pair: the lead byte of a proper pair followed by an invalid value for
  // the second value.
  assertTrue("\uD801\t"[0].code == 0xd801)
  assertTrue("\uD801\t"[1].code == 0x9)
  assertTrue("\uD801\t".codePointAt(0) == 0xd801)
  assertTrue("\uD801\t".codePointAt(1) == 0x9)

  // Test concatenation involving malformed UTF-16.
  val faihu = "\uD800\uDF46"
  val fai = "\uD800"
  val hu = "\uDF46"
  assertTrue(faihu == fai + hu)

  // Substring splits codepoints.
  assertTrue(fai.equals(faihu.substring(0, 1)))
  assertTrue(hu.equals(faihu.substring(1, 2)))
}

// 140x80 + 1 = 11201 chars. Note that the first two characters makes the string have an
// invalid surrogate pair, hence the unicode string is not valid UTF-16.
val VERY_LARGE_INVALID_UNICODE_STRING_LITERAL =
  ("\uD800" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789")

private fun testInvalidEscapes_veryLargeStringLiteral() {
  val length = VERY_LARGE_INVALID_UNICODE_STRING_LITERAL.length
  assertEquals(140 * 80 + 1, length)
  var tailsize = 10

  // To prevent static optimizations from removing the string.
  if (Math.random() > 1) {
    // Never executed.
    tailsize = -1
  }
  assertEquals(
    "0123456789",
    VERY_LARGE_INVALID_UNICODE_STRING_LITERAL.substring(length - tailsize, length),
  )
}
